Название плагина: DKR_SkillDamagePreview
Автор: DarchanKaen (основной плагин), Alx_Yago (с версии 5.0), Dmy (с версии 5.0), Yoji Ojima (отображение текста картинкой)
Версия: 5.0 MV и 3.0 MZ
Дата выхода:
Версия 5.0 для MV - 05.11.2021
Версия 3.0 - 03.06.2021
Версия 2.0 - 02.06.2021
Версия 1.0 - 30.05.2021
Описание плагина:
Плагин позволяет отображать Урон / Лечение , что будет нанесен по одиночной цели, перед нанесением урона.
Финальный урон В ЛЮБОМ СЛУЧАЕ (!) будет немного отличаться от конкретного значения.
Предосмотр урона отображается ТОЛЬКО для скилов с одной фиксированной целью (то есть, не работает для скилов с рандомом выбора цели и атакой всех) не зависимо от количества атак; если атак несколько - выводится суммирующее значение урона.
Нюансы:
1. Предосмотр урона отображается ТОЛЬКО для скилов с одной фиксированной целью.
2. Финальный урон В ЛЮБОМ СЛУЧАЕ (!) будет немного отличаться от конкретного значения.
3. "Урон" или "Лечение" (слова можно заменить в параметрах плагина) - тип воздействия выводится не из формулы урона, а просто из типа цели: если цель Враг - это всегда "Урона", если цель Союзник - это всегда "Лечение".
4. При подсчете урона для предосмотра формула выполняется движком - если у вас сложная формула, используйте тег SkillDamagePreviewSimpleFormula (см.ниже)
5. Номер картинки больше 99 ставить не нужно (!).
Использование плагина(одинаково и для MV , и для MZ...до версии 5.0, она - только на MV !):
Параметры:
В параметрах можно указать: включен ли предосмотр урона по-умолчанию, в каком режиме, номер картинки (задается отображению урона), координаты отображения, а также текста и цвета.
В версии 5.0 (для MV) в параметрах можно также указать, отображается ли крит.урон, используются ли боевые плагины Yanfly и плагин WeaponSkill, общий текст для всего текста предосмотра Урона, а также доп. сдвиг по оси Y для спец. случаев "особенных" боевок.
Примечания скила:
<SkillDamagePreviewSimpleFormula>
Упрощенная формула урона - для случая, если основная формула как-то влияет на персонажей и ее предварительное исполнение не нужно!
</SkillDamagePreviewSimpleFormula>
ИЛИ
SkillDamagePreviewSKIP - если не нужно, что бы для данного скила отображался предосмотр урона в принципе.
И (в версии 5.0 для MV)
<SkillDamagePreviewTextColor>
n - цифра цвета, аналогичная выделения цвета текстом в сообщениях мейкера (1, 2..., 31 - например), она перекрывает дефолтные настройки плагина.
</SkillDamagePreviewTextColor>
Команды:
(в эвенте, в команде "Скрипт")!
DKR.SkillDamagePreview.enableSkillDamagePreview(); - включает предосмотр Урона / Лечения.
DKR.SkillDamagePreview.dissableSkillDamagePreview( ); - отключает предосмотр Урона / Лечения.
DKR.SkillDamagePreview.changePreviewMode('MODE'); - меняет режим предосмотра Урона / Лечения, где 'MODE' - режим, варианты:
'RANGE' - показывает мин. и макс. урон (зависит от Разброса скила);
'VALUE' - показывает конкретное значение урона.
и только для версии 5.0 на MV:
DKR.SkillDamagePreview.OnOffGlobalColor(isEnable, globalTextColor); - включить / выключить один цвет для всего текста предосмотра Урона;
DKR.SkillDamagePreview.OnOffDisplayOnTarget(isEnab le); - показывать текст над целью.
где
isEnable - true (да) / false (нет)
globalTextColor - цвет для всего текста предосмотра Урона.
Код:
Спойлер Код плагина, версия 3.0 (старые версии удалены!):
Спойлер MV, версия 5.0:
Код:/*: *----------------------------------------------------------------------------- * DKR SkillDamagePreview *----------------------------------------------------------------------------- * For: RPGMAKER MV * DKR_SkillDamagePreview_MV_5.js *----------------------------------------------------------------------------- * 05.11.2021 - Версия 5.0.0 *----------------------------------------------------------------------------- * Поставляется AS-IS. * Вся ответственность при использовании - на Пользователе! *----------------------------------------------------------------------------- *----------------------------------------------------------------------------- * @author DarchanKaen, Alx_Yago, Dmy * @target MV * @plugindesc (v.5.0.0) Плагин позволяет отображать урон (лечение), что будет нанесен по одиночной цели, перед нанесением урона. * @help * DKR SkillDamagePreview MV 5.0 * ---------------------------------------------------------------------------- * Благодарности: Alx_Yago и Dmy за помощь в разработке / тестировании плагина * ---------------------------------------------------------------------------- * ---------------------------------------------------------------------------- * Примечаения!: Корректность работы с другими боевыми плагинами, особенно Yanfly, не гарантируется! * ---------------------------------------------------------------------------- * ---Общая информация: * Плагин позволяет отображать урон (лечение), что будет нанесен по одиночной цели, * перед нанесением урона. * Финальный урон В ЛЮБОМ СЛУЧАЕ (!) будет немного отличаться * от конкретного значения. * ---Использование: * --Параметры плагина * В параметрах можно указать: включен ли предосмотр урона по-умолчанию, показывать ли крит-й урон, * используется ли плагин WeaponSkill, используется ли плагин YanflyBattleCore, используется ли другие * боевые плагины Yanfly (для выбора целей, например), использовать ли один и тот же цвет для всего * текста предосмотра, где именно отобажать текст предосмотра, режим предосмотра, * номер картинки (задается отображению урона), координаты отображения, а также текста и цвета. * --В Примечании скила: * <SkillDamagePreviewSimpleFormula> * Упрощенная формула урона - для случая, если основная формула как-то влияет на персонажей * и ее предварительное исполнение не нужно! * </SkillDamagePreviewSimpleFormula> * <SkillDamagePreviewTextColor> * Принудительное отображение текса предосмотра нужным цветом; цвет указывается числом, полная аналогия с * заданием цвета для фрагмента текста в сообщении, но \C[] писать не нужно - только число. * </SkillDamagePreviewTextColor> * ИЛИ * SkillDamagePreviewSKIP - если не нужно, что бы для данного скила отображался предосмотр урона в принципе. * --Команды (для раздела "Скрипт"): * DKR.SkillDamagePreview.enableSkillDamagePreview(); - включает предосмотр Урона / Лечения. * DKR.SkillDamagePreview.dissableSkillDamagePreview(); - отключает предосмотр Урона / Лечения. * DKR.SkillDamagePreview.changePreviewMode('MODE'); - меняет режим предосмотра Урона / Лечения. * где 'MODE' - режим, варианты: * 'RANGE' - показывает мин. и макс. урон (зависит от Разброса скила); * 'VALUE' - показывает конкретное значение урона. * ---------------------------------------------------------------------------- * * @param skillDamagePreviewOn * @type boolean * @desc Включен ли предосмотр урона со старта игры. * @default true * * @param skillIsCritsAffectPreview * @type boolean * @desc Отображать ли критический урон при предосмотре. * @default false * * @param skillIsWeaponSkillUsed * @type boolean * @desc Используется ли плагин WeaponSkill * @default false * * @param skillIsYanflyBattleCoreUsed * @type boolean * @desc Используется ли плагин YanflyBattleCore * @default false * * @param skillIsYanflyWTFUsed * @type boolean * @desc Используется ли плагины Yanfly WTF * @default false * * @param skillIsOnlyGlobalColor * @type boolean * @desc Использовать Цветовой код (\C[?]) для ВСЕГО текста предосмотра. * @default false * * @param skillIsDisplayOnTarget * @type boolean * @desc Отображать предосмотр Над целью, а не сбоку экрана. * @default false * * @param previewMode * @type text * @desc Вариант предосмотра урона: или RANGE (мин. и макс. урон) или VALUE (фикс-е значение урона). * @default RANGE * * @param skillDamagePreviewPicNumber * @type number * @desc Номер картинки, что назначается предосмотру урона. * @default 81 * * @param skillDamagePreviewYOffsetDisplayOnTarget * @type number * @desc Сдвиг вверх картинки предосмотра урона Над целью. * @default 300 * * @param skillDamagePreviewCoordX * @type number * @desc Координата X картинки предосмотра урона. * @default 600 * * @param skillDamagePreviewCoordY * @type number * @desc Координата Y картинки предосмотра урона. * @default 300 * * @param enemyDamageWord * @type text * @desc Текст при выборе скила на Врага. * @default Урон * * @param allyDamageWord * @type text * @desc Текст при выборе скила на Союзника. * @default Лечение * * @param preDamageWord * @type text * @desc Текст перед значениями урона. * @default , ~Σ: * * @param betweenMinMaxDamageWord * @type text * @desc Текст между мин. и макс. уроном. * @default ... * * @param globalColorTag * @type number * @desc Цветовой код (\C[?]) для ВСЕГО текста . * @default 23 * * @param normalColorTag * @type number * @desc Цветовой код (\C[?]) обычного текста . * @default 0 * * @param enemyDamageWordColorTag * @type number * @desc Цветовой код (\C[?]) обычного текста скила на Врага. * @default 10 * * @param allyDamageWordColorTag * @type number * @desc Цветовой код (\C[?]) обычного текста скила на Союзника. * @default 11 * * @param minDamageColorTag * @type number * @desc Цветовой код (\C[?]) минимального урона. * @default 14 * * @param betweenDamageColorTag * @type number * @desc Цветовой код (\C[?]) текста между мин. и макс. уроном. * @default 27 * * @param maxDamageColorTag * @type number * @desc Цветовой код (\C[?]) максимального урона. * @default 27 */ var Imported = Imported || {}; Imported.DKR_SkillDamagePreview = true; var DKR = DKR || {}; DKR.SkillDamagePreview = DKR.SkillDamagePreview || {}; DKR.SkillDamagePreview.version = 5.0; DKR.SkillDamagePreview.parameters = PluginManager.parameters('DKR_SkillDamagePreview_MV_5'); ( () => { DKR.SkillDamagePreview.skillDamagePreviewOn = (DKR.SkillDamagePreview.parameters['skillDamagePreviewOn']=== 'true') ? true : false; DKR.SkillDamagePreview.previewMode = DKR.SkillDamagePreview.parameters['previewMode'] || 'RANGE'; DKR.SkillDamagePreview.skillIsCritsAffectPreview = (DKR.SkillDamagePreview.parameters['skillIsCritsAffectPreview']=== 'true') ? true : false; DKR.SkillDamagePreview.skillIsWeaponSkillUsed = (DKR.SkillDamagePreview.parameters['skillIsWeaponSkillUsed']=== 'true') ? true : false; DKR.SkillDamagePreview.skillIsYanflyBattleCoreUsed = (DKR.SkillDamagePreview.parameters['skillIsYanflyBattleCoreUsed']=== 'true') ? true : false; DKR.SkillDamagePreview.skillIsYanflyWTFUsed = (DKR.SkillDamagePreview.parameters['skillIsYanflyWTFUsed']=== 'true') ? true : false; DKR.SkillDamagePreview.skillIsOnlyGlobalColor = (DKR.SkillDamagePreview.parameters['skillIsOnlyGlobalColor']=== 'true') ? true : false; DKR.SkillDamagePreview.skillIsDisplayOnTarget = (DKR.SkillDamagePreview.parameters['skillIsDisplayOnTarget']=== 'true') ? true : false; DKR.SkillDamagePreview.selectedSkill = null; DKR.SkillDamagePreview.isTargetEnemy = true; let skillDamagePreviewPicNumber = Number(DKR.SkillDamagePreview.parameters['skillDamagePreviewPicNumber']) || 81; let skillDamagePreviewYOffsetDisplayOnTarget = Number(DKR.SkillDamagePreview.parameters['skillDamagePreviewYOffsetDisplayOnTarget']) || 300; let skillDamagePreviewCoordX = Number(DKR.SkillDamagePreview.parameters['skillDamagePreviewCoordX']) || 600; let skillDamagePreviewCoordY = Number(DKR.SkillDamagePreview.parameters['skillDamagePreviewCoordY']) || 300; const skillDamagePreviewOrigin = 0; const skillDamagePreviewScaleX = 100; const skillDamagePreviewScaleY = 100; const skillDamagePreviewOpacity = 255; const skillDamagePreviewBlendMode = 0; const defaultAttackSkillId = 1; let textPictureText = ''; let globalColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['globalColorTag']) + ']' || '\\C[23]'; let normalColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['normalColorTag']) + ']' || '\\C[0]'; let enemyDamageWordColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['enemyDamageWordColorTag']) + ']' || '\\C[10]'; let allyDamageWordColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['allyDamageWordColorTag']) + ']' || '\\C[11]'; let minDamageColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['minDamageColorTag']) + ']' || '\\C[14]'; let betweenDamageColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['betweenDamageColorTag']) + ']' || '\\C[27]'; let maxDamageColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['maxDamageColorTag']) + ']' || '\\C[18]'; let enemyDamageWord = DKR.SkillDamagePreview.parameters['enemyDamageWord'] || 'Урон'; let allyDamageWord = DKR.SkillDamagePreview.parameters['allyDamageWord'] || 'Лечение'; let preDamageWord = DKR.SkillDamagePreview.parameters['preDamageWord'] || ', ~Σ:'; let betweenMinMaxDamageWord = DKR.SkillDamagePreview.parameters['betweenMinMaxDamageWord'] || '...'; let isSelectedObjectSkill = false; let targetCoordX = 0; let targetCoordY = 0; //-4.0_NEW__GLOBAL TEXT COLOR: begin if(true === DKR.SkillDamagePreview.skillIsOnlyGlobalColor){ normalColorTag = ''; enemyDamageWordColorTag = ''; allyDamageWordColorTag = ''; minDamageColorTag = ''; betweenDamageColorTag = ''; maxDamageColorTag = ''; } //-4.0_NEW: end DKR.SkillDamagePreview.Window_SkillList__UpdateHelp = Window_SkillList.prototype.updateHelp; Window_SkillList.prototype.updateHelp = function(){ DKR.SkillDamagePreview.Window_SkillList__UpdateHelp.call(this); if(undefined === this.item()){ console.log('DKR.SkillDamagePreview: skill undefined...'); return false; } DKR.SkillDamagePreview.selectedSkill = this.item(); isSelectedObjectSkill = true; } DKR.SkillDamagePreview.setAttack = Game_Action.prototype.setAttack; Game_Action.prototype.setAttack = function() { DKR.SkillDamagePreview.setAttack.call(this); isSelectedObjectSkill = true; let weaponSkillId = defaultAttackSkillId; if(true === DKR.SkillDamagePreview.skillIsWeaponSkillUsed){ let actor = BattleManager.actor(); if(false === actor.hasNoWeapons()){ let weapon = actor.weapons()[0]; try{ weaponSkillId = weapon.meta.skill_id; }catch(error){ weaponSkillId = defaultAttackSkillId; } if(undefined === weaponSkillId){ weaponSkillId = defaultAttackSkillId; } } } DKR.SkillDamagePreview.selectedSkill = $dataSkills[weaponSkillId]; }; DKR.SkillDamagePreview.Window_BattleEnemy__select = Window_BattleEnemy.prototype.select; Window_BattleEnemy.prototype.select = function(index){ DKR.SkillDamagePreview.Window_BattleEnemy__select.call(this, index); //console.log('---DKR_SELECT: enemy!...this:', this); if(false === DKR.SkillDamagePreview.skillIsYanflyWTFUsed){ if(true === DKR.SkillDamagePreview.skillDamagePreviewOn && index > -1){ DKR.SkillDamagePreview.isTargetEnemy = true; DKR.SkillDamagePreview.showSkillDamagePreview(index, false); } }else{ if(true === DKR.SkillDamagePreview.skillDamagePreviewOn){ //console.log('---this.enemy():', this.enemy()); if( undefined !== this.enemy() && null !== this.enemy() && 'ALL ALLIES' !== this.enemy() && 'ALL ENEMIES' !== this.enemy() ){ if( true === this.enemy().isActor() ){ DKR.SkillDamagePreview.isTargetEnemy = false; }else{ DKR.SkillDamagePreview.isTargetEnemy = true; } DKR.SkillDamagePreview.showSkillDamagePreview(this.enemy(), true); } } } } DKR.SkillDamagePreview.Window_BattleActor__select = Window_BattleActor.prototype.select; Window_BattleActor.prototype.select = function(index){ DKR.SkillDamagePreview.Window_BattleActor__select.call(this, index); if(true === DKR.SkillDamagePreview.skillDamagePreviewOn && index > -1){ DKR.SkillDamagePreview.isTargetEnemy = false; DKR.SkillDamagePreview.showSkillDamagePreview(index, false); } } DKR.SkillDamagePreview.Window_BattleEnemy__hide = Window_BattleEnemy.prototype.hide; Window_BattleEnemy.prototype.hide = function() { DKR.SkillDamagePreview.Window_BattleEnemy__hide.call(this); $gameScreen.erasePicture(skillDamagePreviewPicNumber); isSelectedObjectSkill = false; }; DKR.SkillDamagePreview.Window_BattleActor__hide = Window_BattleActor.prototype.hide; Window_BattleActor.prototype.hide = function() { DKR.SkillDamagePreview.Window_BattleActor__hide.call(this); $gameScreen.erasePicture(skillDamagePreviewPicNumber); isSelectedObjectSkill = false; }; DKR.SkillDamagePreview.Scene_Battle__onItemOk = Scene_Battle.prototype.onItemOk; Scene_Battle.prototype.onItemOk = function() { DKR.SkillDamagePreview.Scene_Battle__onItemOk.call(this); $gameScreen.erasePicture(skillDamagePreviewPicNumber); isSelectedObjectSkill = false; }; DKR.SkillDamagePreview.showSkillDamagePreview = function(enemyIndex, isYanflyWTFMode){ let isTagretPlayer = false; if(false === isSelectedObjectSkill){ return false; } let enemy = null; let enemiesTroop = null; if(false === isYanflyWTFMode){ if(true === DKR.SkillDamagePreview.isTargetEnemy){ if(false === DKR.SkillDamagePreview.skillIsYanflyBattleCoreUsed){ enemiesTroop = $gameTroop.aliveMembers(); }else{ enemiesTroop = $gameTroop.aliveMembers().sort(function(a, b) { if (a.spritePosX() === b.spritePosX()) { return a.spritePosY() - b.spritePosY(); } return a.spritePosX() - b.spritePosX(); }); } if(false === DKR.SkillDamagePreview.skillIsYanflyWTFUsed){ enemy = enemiesTroop[enemyIndex]; }else{ enemy = this.enemy(); } //console.log('_ENEMY_INDEX:', enemyIndex); //console.log('_TARGET:', enemy); //console.log('_ENEMIES TROOP:', enemiesTroop); if(enemyIndex >= enemiesTroop.length){ console.log('_YANFLY_TARGET_PARADOX !!!'); return false; } }else{ enemy = $gameParty.members()[enemyIndex]; isTagretPlayer = true; //console.log('_TARGET: player'); } }else if(true === isYanflyWTFMode){ if(true === DKR.SkillDamagePreview.isTargetEnemy){ enemy = enemyIndex; isTagretPlayer = false; }else{ enemy = enemyIndex isTagretPlayer = true; } } //console.log('__DKR.SkillDamagePreview.isTargetEnemy:', DKR.SkillDamagePreview.isTargetEnemy); //console.log('__enemy, isTagretPlayer:', enemy, isTagretPlayer); let actor = BattleManager.actor(); let skill = DKR.SkillDamagePreview.selectedSkill; if(null === actor){ return false; } let skillSkipOrSimpleFormula = parseSkillNoteForSOrSF(skill); //-4.0_NEW__SKILL TEXT COLOR: begin let skilltTxtColor = parseSkillNoteForSTC(skill); //console.log('skilltTxtColor:', skilltTxtColor); if('NONE' !== skilltTxtColor){ DKR.SkillDamagePreview.OnOffGlobalColor(true, skilltTxtColor); } //-4.0_NEW__SKILL TEXT COLOR: begin if('SKIP' === skillSkipOrSimpleFormula){ return false; }else if('NONE' === skillSkipOrSimpleFormula){ skillSkipOrSimpleFormula = null; } let isSkillCritical = Math.random() < calcIsSkillCritical(enemy, actor, skill); if(false === DKR.SkillDamagePreview.skillIsCritsAffectPreview){ isSkillCritical = false; } let totalDamageValue = 0; let currentDamageValue = 0; for(let n = 0; n < skill.repeats; n++){ currentDamageValue = makeDamageValue(enemy, actor, skill, isSkillCritical, skillSkipOrSimpleFormula); totalDamageValue += currentDamageValue; } let [minDamage, maxDamage] = getMinMaxDamage(totalDamageValue, skill.damage.variance); //-4.0_NEW__DISPLAY ON TARGET: begin if(false === isTagretPlayer && true === DKR.SkillDamagePreview.skillIsDisplayOnTarget){ targetCoordX = enemy._screenX; targetCoordY = enemy._screenY - skillDamagePreviewYOffsetDisplayOnTarget; skillDamagePreviewCoordX = targetCoordX; skillDamagePreviewCoordY = targetCoordY; }else{ skillDamagePreviewCoordX = Number(DKR.SkillDamagePreview.parameters['skillDamagePreviewCoordX']) || 600; skillDamagePreviewCoordY = Number(DKR.SkillDamagePreview.parameters['skillDamagePreviewCoordY']) || 300; } //-4.0_NEW__DISPLAY ON TARGET: end drawSkillDamagePreviewOnEnemy(minDamage, maxDamage); if(true === DKR.SkillDamagePreview.skillIsOnlyGlobalColor){ DKR.SkillDamagePreview.OnOffGlobalColor(true); }else{ DKR.SkillDamagePreview.OnOffGlobalColor(false); } } let parseSkillNoteForSOrSF = function(skill){ const tag = 'SkillDamagePreviewSimpleFormula'; const skipWord = 'SkillDamagePreviewSKIP'; let notedata = skill.note.split(/[\r\n]+/); let formulaText = 'NONE'; if(true === skill.note.includes(skipWord)){ formulaText = 'SKIP'; return formulaText; } let matchCount = 0; for (let i = 0; i < notedata.length; i++) { let line = notedata[i]; if (notedata[i].match(tag)) { matchCount++; if(2 === matchCount){ break; }else{ formulaText = '\r\n'; continue; } } if(1 === matchCount){ formulaText += notedata[i].trim() + '\r\n' } } return formulaText; } let parseSkillNoteForSTC = function(skill){ const tag = 'SkillDamagePreviewTextColor'; let skillTextColor = 'NONE'; let notedata = skill.note.split(/[\r\n]+/); let matchCount = 0; for (let i = 0; i < notedata.length; i++) { let line = notedata[i]; if (notedata[i].match(tag)) { matchCount++; if(2 === matchCount){ break; }else{ skillTextColor = '\r\n'; continue; } } if(1 === matchCount){ skillTextColor += notedata[i].trim() + '\r\n' } } return skillTextColor; } let getMinMaxDamage = function(damage, variance){ let minDamage = 0; let maxDamage = 0; let minMaxDamage = []; let diffByVariance = 0; if('RANGE' === DKR.SkillDamagePreview.previewMode){ let diffByVariance = Math.round( damage * (variance / 100) ); minDamage = Math.round( damage - (diffByVariance + (diffByVariance / 4) ) ); maxDamage = Math.round( damage + diffByVariance ); }else if('VALUE' === DKR.SkillDamagePreview.previewMode){ minDamage = damage; maxDamage = damage; } minMaxDamage = [minDamage, maxDamage]; return minMaxDamage; } let drawSkillDamagePreviewOnEnemy = function(minDamage, maxDamage){ let damageTypeWord = ''; let damageTypeColorTag = ''; if(true === DKR.SkillDamagePreview.isTargetEnemy){ damageTypeWord = enemyDamageWord; damageTypeColorTag = enemyDamageWordColorTag; }else{ minDamage = Math.abs(minDamage); maxDamage = Math.abs(maxDamage); damageTypeWord = allyDamageWord; damageTypeColorTag = allyDamageWordColorTag; } textPictureText = `${globalColorTag} ${damageTypeColorTag}${damageTypeWord}${betweenDamageColorTag}${preDamageWord} ${minDamageColorTag}${minDamage}${betweenDamageColorTag}${betweenMinMaxDamageWord}${maxDamageColorTag}${maxDamage}${normalColorTag}`; $gameScreen.showPicture(skillDamagePreviewPicNumber, '', skillDamagePreviewOrigin, skillDamagePreviewCoordX, skillDamagePreviewCoordY, skillDamagePreviewScaleX, skillDamagePreviewScaleY, skillDamagePreviewOpacity, skillDamagePreviewBlendMode); } DKR.SkillDamagePreview.enableSkillDamagePreview = function(){ DKR.SkillDamagePreview.skillDamagePreviewOn = true; } DKR.SkillDamagePreview.dissableSkillDamagePreview = function(){ DKR.SkillDamagePreview.skillDamagePreviewOn = false; } DKR.SkillDamagePreview.changePreviewMode = function(pMode){ DKR.SkillDamagePreview.previewMode = pMode; } DKR.SkillDamagePreview.OnOffGlobalColor = function(isEnable, globalTC = 'NONE'){ if('NONE' === globalTC){ DKR.SkillDamagePreview.skillIsOnlyGlobalColor = isEnable; } //DKR.SkillDamagePreview.skillIsOnlyGlobalColor = isEnable; if(false === isEnable){ globalColorTag = ''; normalColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['normalColorTag']) + ']' || '\\C[0]'; enemyDamageWordColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['enemyDamageWordColorTag']) + ']' || '\\C[10]'; allyDamageWordColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['allyDamageWordColorTag']) + ']' || '\\C[11]'; minDamageColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['minDamageColorTag']) + ']' || '\\C[14]'; betweenDamageColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['betweenDamageColorTag']) + ']' || '\\C[27]'; maxDamageColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['maxDamageColorTag']) + ']' || '\\C[18]'; }else{ if('NONE' === globalTC){ globalColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['globalColorTag']) + ']' || '\\C[23]'; }else{ globalColorTag = '\\C[' + Number(globalTC) + ']'; } normalColorTag = ''; enemyDamageWordColorTag = ''; allyDamageWordColorTag = ''; minDamageColorTag = ''; betweenDamageColorTag = ''; maxDamageColorTag = ''; } } DKR.SkillDamagePreview.OnOffDisplayOnTarget = function(isEnable){ DKR.SkillDamagePreview.skillIsDisplayOnTarget = isEnable; } //---COPY PAST CORELIB: BEGIN let makeDamageValue = function(target, actor, skill, isCritical, skillDamageSimpleFormula) { const item = skill; const baseValue = evalDamageFormula(target, actor, skill, skillDamageSimpleFormula); let value = baseValue * calcElementRate(target, actor, skill); if (isPhysical(skill)) { value *= target.pdr; } if (isMagical(skill)) { value *= target.mdr; } if (baseValue < 0) { value *= target.rec; } if (isCritical) { value = applyCritical(value); } value = applyVariance(value, item.damage.variance); value = applyGuard(value, target); value = Math.round(value); return value; }; let calcIsSkillCritical = function(target, actor, skill) { return skill.damage.critical ? actor.cri * (1 - target.cev) : 0; }; let evalDamageFormula = function(target, actor, skill, skillDamageSimpleFormula) { try { let skillDamageFormula = null; if(null === skillDamageSimpleFormula){ skillDamageFormula = skill.damage.formula; }else{ skillDamageFormula = skillDamageSimpleFormula; } const a = actor; const b = target; const v = $gameVariables._data; const sign = [3, 4].includes(skill.damage.type) ? -1 : 1; const value = Math.max(eval(skillDamageFormula), 0) * sign; return isNaN(value) ? 0 : value; } catch (e) { return 0; } }; let calcElementRate = function(target, actor, skill) { if (skill.damage.elementId < 0) { return elementsMaxRate(target, actor.attackElements()); } else { return target.elementRate(skill.damage.elementId); } }; let elementsMaxRate = function(target, elements) { if (elements.length > 0) { const rates = elements.map(elementId => target.elementRate(elementId)); return Math.max(...rates); } else { return 1; } }; let isPhysical = function(skill) { return skill.hitType === Game_Action.HITTYPE_PHYSICAL; }; let isMagical = function(skill) { return skill.hitType === Game_Action.HITTYPE_MAGICAL; }; let applyCritical = function(damage) { return damage * 3; }; let applyVariance = function(damage, variance) { const amp = Math.floor(Math.max((Math.abs(damage) * variance) / 100, 0)); const v = Math.randomInt(amp + 1) + Math.randomInt(amp + 1) - amp; return damage >= 0 ? damage + v : damage - v; }; let applyGuard = function(damage, target) { return damage / (damage > 0 && target.isGuard() ? 2 * target.grd : 1); }; //---COPY PAST CORELIB: END //---Thanks to Yoji Ojima: BEGIN const _Game_Picture_show = Game_Picture.prototype.show; Game_Picture.prototype.show = function() { _Game_Picture_show.apply(this, arguments); if (this._name === "" && textPictureText) { this.mzkp_text = textPictureText; this.mzkp_textChanged = true; textPictureText = ''; } }; const _Sprite_Picture_destroy = Sprite_Picture.prototype.destroy; Sprite_Picture.prototype.destroy = function() { destroyTextPictureBitmap(this.bitmap); _Sprite_Picture_destroy.apply(this, arguments); }; const _Sprite_Picture_updateBitmap = Sprite_Picture.prototype.updateBitmap; Sprite_Picture.prototype.updateBitmap = function() { _Sprite_Picture_updateBitmap.apply(this, arguments); if (this.visible && this._pictureName === "") { const picture = this.picture(); const text = picture ? picture.mzkp_text || "" : ""; const textChanged = picture && picture.mzkp_textChanged; if (this.mzkp_text !== text || textChanged) { this.mzkp_text = text; destroyTextPictureBitmap(this.bitmap); this.bitmap = createTextPictureBitmap(text); picture.mzkp_textChanged = false; } } else { this.mzkp_text = ""; } }; function createTextPictureBitmap(text) { const tempWindow = new Window_Base(new Rectangle()); const size = {width:750, height: 300}; //MV: hardcode //MZ: textSizeEx(text) tempWindow.padding = 0; tempWindow.move(0, 0, size.width, size.height); tempWindow.createContents(); tempWindow.drawTextEx(text, 0, 0, 0); const bitmap = tempWindow.contents; tempWindow.contents = null; tempWindow.destroy(); bitmap.mzkp_isTextPicture = true; return bitmap; } function destroyTextPictureBitmap(bitmap) { if (bitmap && bitmap.mzkp_isTextPicture) { bitmap.clear(); } } //---Thanks to Yoji Ojima: END })();
Спойлер MV, версия 3.0:
Код:/*: *----------------------------------------------------------------------------- * DKR SkillDamagePreview *----------------------------------------------------------------------------- * For: RPGMAKER MV * DKR_SkillDamagePreview_MV_3.js *----------------------------------------------------------------------------- * 02.06.2021 - Версия 3.0.0 *----------------------------------------------------------------------------- * Поставляется AS-IS. * Вся ответственность при использовании - на Пользователе! *----------------------------------------------------------------------------- *----------------------------------------------------------------------------- * @author DarchanKaen * @target MV * @plugindesc (v.3.0.0) Плагин позволяет отображать урон (лечение), что будет нанесен по одиночной цели, перед нанесением урона. * @help * DKR SkillDamagePreview MV 3.0 * ---------------------------------------------------------------------------- * ---Общая информация: * Плагин позволяет отображать урон (лечение), что будет нанесен по одиночной цели, * перед нанесением урона. * Финальный урон В ЛЮБОМ СЛУЧАЕ (!) будет немного отличаться * от конкретного значения. * ---Использование: * --Параметры плагина * В параметрах можно указать: включен ли предосмотр урона по-умолчанию, в каком режиме, * номер картинки (задается отображению урона), координаты отображения, а также текста и цвета. * --В Примечании скила: * <SkillDamagePreviewSimpleFormula> * Упрощенная формула урона - для случая, если основная формула как-то влияет на персонажей * и ее предварительное исполнение не нужно! * </SkillDamagePreviewSimpleFormula> * ИЛИ * SkillDamagePreviewSKIP - если не нужно, что бы для данного скила отображался предосмотр урона в принципе. * --Команды (для раздела "Скрипт"): * DKR.SkillDamagePreview.enableSkillDamagePreview(); - включает предосмотр Урона / Лечения. * DKR.SkillDamagePreview.dissableSkillDamagePreview(); - отключает предосмотр Урона / Лечения. * DKR.SkillDamagePreview.changePreviewMode('MODE'); - меняет режим предосмотра Урона / Лечения. * где 'MODE' - режим, варианты: * 'RANGE' - показывает мин. и макс. урон (зависит от Разброса скила); * 'VALUE' - показывает конкретное значение урона. * ---------------------------------------------------------------------------- * ----Версия 5.0 (для MV) * Добавлена совместимость с плагинами Yanfly * ---------------------------------------------------------------------------- * * @param skillDamagePreviewOn * @type boolean * @desc Включен ли предосмотр урона со старта игры. * @default true * * @param skillIsCritsAffectPreview * @type boolean * @desc Отображать ли критический урон при предосмотре. * @default false * * @param skillIsWeaponSkillUsed * @type boolean * @desc Используется ли плагин WeaponSkill * @default false * * @param previewMode * @type text * @desc Вариант предосмотра урона: или RANGE (мин. и макс. урон) или VALUE (фикс-е значение урона). * @default RANGE * * @param skillDamagePreviewPicNumber * @type number * @desc Номер картинки, что назначается предосмотру урона. * @default 81 * * @param skillDamagePreviewCoordX * @type number * @desc Координата X картинки предосмотра урона. * @default 600 * * @param skillDamagePreviewCoordY * @type number * @desc Координата Y картинки предосмотра урона. * @default 300 * * @param enemyDamageWord * @type text * @desc Текст при выборе скила на Врага. * @default Урон * * @param allyDamageWord * @type text * @desc Текст при выборе скила на Союзника. * @default Лечение * * @param preDamageWord * @type text * @desc Текст перед значениями урона. * @default , ~Σ: * * @param betweenMinMaxDamageWord * @type text * @desc Текст между мин. и макс. уроном. * @default ... * * @param normalColorTag * @type number * @desc Цветовой код (\C[?]) обычного текста . * @default 0 * * @param enemyDamageWordColorTag * @type number * @desc Цветовой код (\C[?]) обычного текста скила на Врага. * @default 10 * * @param allyDamageWordColorTag * @type number * @desc Цветовой код (\C[?]) обычного текста скила на Союзника. * @default 11 * * @param minDamageColorTag * @type number * @desc Цветовой код (\C[?]) минимального урона. * @default 14 * * @param betweenDamageColorTag * @type number * @desc Цветовой код (\C[?]) текста между мин. и макс. уроном. * @default 27 * * @param maxDamageColorTag * @type number * @desc Цветовой код (\C[?]) максимального урона. * @default 27 */ var Imported = Imported || {}; Imported.DKR_SkillDamagePreview = true; var DKR = DKR || {}; DKR.SkillDamagePreview = DKR.SkillDamagePreview || {}; DKR.SkillDamagePreview.version = 3.0; DKR.SkillDamagePreview.parameters = PluginManager.parameters('DKR_SkillDamagePreview_MV_3'); ( () => { DKR.SkillDamagePreview.skillDamagePreviewOn = (DKR.SkillDamagePreview.parameters['skillDamagePreviewOn']=== 'true') ? true : false; DKR.SkillDamagePreview.previewMode = DKR.SkillDamagePreview.parameters['previewMode'] || 'RANGE'; DKR.SkillDamagePreview.skillIsCritsAffectPreview = (DKR.SkillDamagePreview.parameters['skillIsCritsAffectPreview']=== 'true') ? true : false; DKR.SkillDamagePreview.skillIsWeaponSkillUsed = (DKR.SkillDamagePreview.parameters['skillIsWeaponSkillUsed']=== 'true') ? true : false; DKR.SkillDamagePreview.selectedSkill = null; DKR.SkillDamagePreview.isTargetEnemy = true; let skillDamagePreviewPicNumber = Number(DKR.SkillDamagePreview.parameters['skillDamagePreviewPicNumber']) || 81; let skillDamagePreviewCoordX = Number(DKR.SkillDamagePreview.parameters['skillDamagePreviewCoordX']) || 600; let skillDamagePreviewCoordY = Number(DKR.SkillDamagePreview.parameters['skillDamagePreviewCoordY']) || 300; const skillDamagePreviewOrigin = 0; const skillDamagePreviewScaleX = 100; const skillDamagePreviewScaleY = 100; const skillDamagePreviewOpacity = 255; const skillDamagePreviewBlendMode = 0; const defaultAttackSkillId = 1; let textPictureText = ''; let normalColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['normalColorTag']) + ']' || '\\C[0]'; let enemyDamageWordColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['enemyDamageWordColorTag']) + ']' || '\\C[10]'; let allyDamageWordColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['allyDamageWordColorTag']) + ']' || '\\C[11]'; let minDamageColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['minDamageColorTag']) + ']' || '\\C[14]'; let betweenDamageColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['betweenDamageColorTag']) + ']' || '\\C[27]'; let maxDamageColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['maxDamageColorTag']) + ']' || '\\C[18]'; let enemyDamageWord = DKR.SkillDamagePreview.parameters['enemyDamageWord'] || 'Урон'; let allyDamageWord = DKR.SkillDamagePreview.parameters['allyDamageWord'] || 'Лечение'; let preDamageWord = DKR.SkillDamagePreview.parameters['preDamageWord'] || ', ~Σ:'; let betweenMinMaxDamageWord = DKR.SkillDamagePreview.parameters['betweenMinMaxDamageWord'] || '...'; let isSelectedObjectSkill = false; DKR.SkillDamagePreview.Window_SkillList__UpdateHelp = Window_SkillList.prototype.updateHelp; Window_SkillList.prototype.updateHelp = function(){ DKR.SkillDamagePreview.Window_SkillList__UpdateHelp.call(this); if(undefined === this.item()){ console.log('DKR.SkillDamagePreview: skill undefined...'); return false; } DKR.SkillDamagePreview.selectedSkill = this.item(); isSelectedObjectSkill = true; } DKR.SkillDamagePreview.setAttack = Game_Action.prototype.setAttack; Game_Action.prototype.setAttack = function() { DKR.SkillDamagePreview.setAttack.call(this); isSelectedObjectSkill = true; let weaponSkillId = defaultAttackSkillId; if(true === DKR.SkillDamagePreview.skillIsWeaponSkillUsed){ let actor = BattleManager.actor(); if(false === actor.hasNoWeapons()){ let weapon = actor.weapons()[0]; try{ weaponSkillId = weapon.meta.skill_id; }catch(error){ weaponSkillId = defaultAttackSkillId; } if(undefined === weaponSkillId){ weaponSkillId = defaultAttackSkillId; } } } DKR.SkillDamagePreview.selectedSkill = $dataSkills[weaponSkillId]; }; DKR.SkillDamagePreview.Window_BattleEnemy__select = Window_BattleEnemy.prototype.select; Window_BattleEnemy.prototype.select = function(index){ DKR.SkillDamagePreview.Window_BattleEnemy__select.call(this, index); if(true === DKR.SkillDamagePreview.skillDamagePreviewOn && index > -1){ DKR.SkillDamagePreview.isTargetEnemy = true; DKR.SkillDamagePreview.showSkillDamagePreview(index); } } DKR.SkillDamagePreview.Window_BattleActor__select = Window_BattleActor.prototype.select; Window_BattleActor.prototype.select = function(index){ DKR.SkillDamagePreview.Window_BattleActor__select.call(this, index); if(true === DKR.SkillDamagePreview.skillDamagePreviewOn && index > -1){ DKR.SkillDamagePreview.isTargetEnemy = false; DKR.SkillDamagePreview.showSkillDamagePreview(index); } } DKR.SkillDamagePreview.Window_BattleEnemy__hide = Window_BattleEnemy.prototype.hide; Window_BattleEnemy.prototype.hide = function() { DKR.SkillDamagePreview.Window_BattleEnemy__hide.call(this); $gameScreen.erasePicture(skillDamagePreviewPicNumber); isSelectedObjectSkill = false; }; DKR.SkillDamagePreview.Window_BattleActor__hide = Window_BattleActor.prototype.hide; Window_BattleActor.prototype.hide = function() { DKR.SkillDamagePreview.Window_BattleActor__hide.call(this); $gameScreen.erasePicture(skillDamagePreviewPicNumber); isSelectedObjectSkill = false; }; DKR.SkillDamagePreview.Scene_Battle__onItemOk = Scene_Battle.prototype.onItemOk; Scene_Battle.prototype.onItemOk = function() { DKR.SkillDamagePreview.Scene_Battle__onItemOk.call(this); $gameScreen.erasePicture(skillDamagePreviewPicNumber); isSelectedObjectSkill = false; }; DKR.SkillDamagePreview.showSkillDamagePreview = function(enemyIndex){ if(false === isSelectedObjectSkill){ return false; } let enemy = null; let enemiesTroop = null; if(true === DKR.SkillDamagePreview.isTargetEnemy){ enemiesTroop = $gameTroop.aliveMembers(); enemy = enemiesTroop[enemyIndex]; }else{ enemy = $gameParty.members()[enemyIndex]; } let actor = BattleManager.actor(); let skill = DKR.SkillDamagePreview.selectedSkill; if(null === actor){ return false; } let skillSkipOrSimpleFormula = parseSkillNoteForSOrSF(skill); if('SKIP' === skillSkipOrSimpleFormula){ return false; }else if('NONE' === skillSkipOrSimpleFormula){ skillSkipOrSimpleFormula = null; } let isSkillCritical = Math.random() < calcIsSkillCritical(enemy, actor, skill); if(false === DKR.SkillDamagePreview.skillIsCritsAffectPreview){ isSkillCritical = false; } let totalDamageValue = 0; let currentDamageValue = 0; for(let n = 0; n < skill.repeats; n++){ currentDamageValue = makeDamageValue(enemy, actor, skill, isSkillCritical, skillSkipOrSimpleFormula); totalDamageValue += currentDamageValue; } let [minDamage, maxDamage] = getMinMaxDamage(totalDamageValue, skill.damage.variance); drawSkillDamagePreviewOnEnemy(minDamage, maxDamage); } let parseSkillNoteForSOrSF = function(skill){ const tag = 'SkillDamagePreviewSimpleFormula'; const skipWord = 'SkillDamagePreviewSKIP'; let notedata = skill.note.split(/[\r\n]+/); let formulaText = 'NONE'; if(true === skill.note.includes(skipWord)){ formulaText = 'SKIP'; return formulaText; } let matchCount = 0; for (let i = 0; i < notedata.length; i++) { let line = notedata[i]; if (notedata[i].match(tag)) { matchCount++; if(2 === matchCount){ break; }else{ formulaText = '\r\n'; continue; } } if(1 === matchCount){ formulaText += notedata[i].trim() + '\r\n' } } return formulaText; } let getMinMaxDamage = function(damage, variance){ let minDamage = 0; let maxDamage = 0; let minMaxDamage = []; let diffByVariance = 0; if('RANGE' === DKR.SkillDamagePreview.previewMode){ let diffByVariance = Math.round( damage * (variance / 100) ); minDamage = Math.round( damage - (diffByVariance + (diffByVariance / 4) ) ); maxDamage = Math.round( damage + diffByVariance ); }else if('VALUE' === DKR.SkillDamagePreview.previewMode){ minDamage = damage; maxDamage = damage; } minMaxDamage = [minDamage, maxDamage]; return minMaxDamage; } let drawSkillDamagePreviewOnEnemy = function(minDamage, maxDamage){ let damageTypeWord = ''; let damageTypeColorTag = ''; if(true === DKR.SkillDamagePreview.isTargetEnemy){ damageTypeWord = enemyDamageWord; damageTypeColorTag = enemyDamageWordColorTag; }else{ minDamage = Math.abs(minDamage); maxDamage = Math.abs(maxDamage); damageTypeWord = allyDamageWord; damageTypeColorTag = allyDamageWordColorTag; } textPictureText = ` ${damageTypeColorTag}${damageTypeWord}${betweenDamageColorTag}${preDamageWord} ${minDamageColorTag}${minDamage}${betweenDamageColorTag}${betweenMinMaxDamageWord}${maxDamageColorTag}${maxDamage}${normalColorTag}`; $gameScreen.showPicture(skillDamagePreviewPicNumber, '', skillDamagePreviewOrigin, skillDamagePreviewCoordX, skillDamagePreviewCoordY, skillDamagePreviewScaleX, skillDamagePreviewScaleY, skillDamagePreviewOpacity, skillDamagePreviewBlendMode); } DKR.SkillDamagePreview.enableSkillDamagePreview = function(){ DKR.SkillDamagePreview.skillDamagePreviewOn = true; } DKR.SkillDamagePreview.dissableSkillDamagePreview = function(){ DKR.SkillDamagePreview.skillDamagePreviewOn = false; } DKR.SkillDamagePreview.changePreviewMode = function(pMode){ DKR.SkillDamagePreview.previewMode = pMode; } //---COPY PAST CORELIB: BEGIN let makeDamageValue = function(target, actor, skill, isCritical, skillDamageSimpleFormula) { const item = skill; const baseValue = evalDamageFormula(target, actor, skill, skillDamageSimpleFormula); let value = baseValue * calcElementRate(target, actor, skill); if (isPhysical(skill)) { value *= target.pdr; } if (isMagical(skill)) { value *= target.mdr; } if (baseValue < 0) { value *= target.rec; } if (isCritical) { value = applyCritical(value); } value = applyVariance(value, item.damage.variance); value = applyGuard(value, target); value = Math.round(value); return value; }; let calcIsSkillCritical = function(target, actor, skill) { return skill.damage.critical ? actor.cri * (1 - target.cev) : 0; }; let evalDamageFormula = function(target, actor, skill, skillDamageSimpleFormula) { try { let skillDamageFormula = null; if(null === skillDamageSimpleFormula){ skillDamageFormula = skill.damage.formula; }else{ skillDamageFormula = skillDamageSimpleFormula; } const a = actor; const b = target; const v = $gameVariables._data; const sign = [3, 4].includes(skill.damage.type) ? -1 : 1; const value = Math.max(eval(skillDamageFormula), 0) * sign; return isNaN(value) ? 0 : value; } catch (e) { return 0; } }; let calcElementRate = function(target, actor, skill) { if (skill.damage.elementId < 0) { return elementsMaxRate(target, actor.attackElements()); } else { return target.elementRate(skill.damage.elementId); } }; let elementsMaxRate = function(target, elements) { if (elements.length > 0) { const rates = elements.map(elementId => target.elementRate(elementId)); return Math.max(...rates); } else { return 1; } }; let isPhysical = function(skill) { return skill.hitType === Game_Action.HITTYPE_PHYSICAL; }; let isMagical = function(skill) { return skill.hitType === Game_Action.HITTYPE_MAGICAL; }; let applyCritical = function(damage) { return damage * 3; }; let applyVariance = function(damage, variance) { const amp = Math.floor(Math.max((Math.abs(damage) * variance) / 100, 0)); const v = Math.randomInt(amp + 1) + Math.randomInt(amp + 1) - amp; return damage >= 0 ? damage + v : damage - v; }; let applyGuard = function(damage, target) { return damage / (damage > 0 && target.isGuard() ? 2 * target.grd : 1); }; //---COPY PAST CORELIB: END //---Thanks to Yoji Ojima: BEGIN const _Game_Picture_show = Game_Picture.prototype.show; Game_Picture.prototype.show = function() { _Game_Picture_show.apply(this, arguments); if (this._name === "" && textPictureText) { this.mzkp_text = textPictureText; this.mzkp_textChanged = true; textPictureText = ''; } }; const _Sprite_Picture_destroy = Sprite_Picture.prototype.destroy; Sprite_Picture.prototype.destroy = function() { destroyTextPictureBitmap(this.bitmap); _Sprite_Picture_destroy.apply(this, arguments); }; const _Sprite_Picture_updateBitmap = Sprite_Picture.prototype.updateBitmap; Sprite_Picture.prototype.updateBitmap = function() { _Sprite_Picture_updateBitmap.apply(this, arguments); if (this.visible && this._pictureName === "") { const picture = this.picture(); const text = picture ? picture.mzkp_text || "" : ""; const textChanged = picture && picture.mzkp_textChanged; if (this.mzkp_text !== text || textChanged) { this.mzkp_text = text; destroyTextPictureBitmap(this.bitmap); this.bitmap = createTextPictureBitmap(text); picture.mzkp_textChanged = false; } } else { this.mzkp_text = ""; } }; function createTextPictureBitmap(text) { const tempWindow = new Window_Base(new Rectangle()); const size = {width:750, height: 300}; //MV: hardcode //MZ: textSizeEx(text) tempWindow.padding = 0; tempWindow.move(0, 0, size.width, size.height); tempWindow.createContents(); tempWindow.drawTextEx(text, 0, 0, 0); const bitmap = tempWindow.contents; tempWindow.contents = null; tempWindow.destroy(); bitmap.mzkp_isTextPicture = true; return bitmap; } function destroyTextPictureBitmap(bitmap) { if (bitmap && bitmap.mzkp_isTextPicture) { bitmap.clear(); } } //---Thanks to Yoji Ojima: END })();
Спойлер MZ, версия 3.0:
Код:/*: *----------------------------------------------------------------------------- * DKR SkillDamagePreview *----------------------------------------------------------------------------- * For: RPGMAKER MZ * DKR_SkillDamagePreview_MZ_3.0.js *----------------------------------------------------------------------------- * 02.06.2021 - Версия 3.0.0 *----------------------------------------------------------------------------- * Поставляется AS-IS. * Вся ответственность при использовании - на Пользователе! *----------------------------------------------------------------------------- *----------------------------------------------------------------------------- * @author DarchanKaen * @target MZ * @plugindesc (v.3.0.0) Плагин позволяет отображать урон (лечение), что будет нанесен по одиночной цели, перед нанесением урона. * @help * DKR SkillDamagePreview MZ 3.0 * ---------------------------------------------------------------------------- * ---Общая информация: * Плагин позволяет отображать урон (лечение), что будет нанесен по одиночной цели, * перед нанесением урона. * Финальный урон В ЛЮБОМ СЛУЧАЕ (!) будет немного отличаться * от конкретного значения. * ---Использование: * --Параметры плагина * В параметрах можно указать: включен ли предосмотр урона по-умолчанию, в каком режиме, * номер картинки (задается отображению урона), координаты отображения, а также текста и цвета. * --В Примечании скила: * <SkillDamagePreviewSimpleFormula> * Упрощенная формула урона - для случая, если основная формула как-то влияет на персонажей * и ее предварительное исполнение не нужно! * </SkillDamagePreviewSimpleFormula> * ИЛИ * SkillDamagePreviewSKIP - если не нужно, что бы для данного скила отображался предосмотр урона в принципе. * --Команды (для раздела "Скрипт"): * DKR.SkillDamagePreview.enableSkillDamagePreview(); - включает предосмотр Урона / Лечения. * DKR.SkillDamagePreview.dissableSkillDamagePreview(); - отключает предосмотр Урона / Лечения. * DKR.SkillDamagePreview.changePreviewMode('MODE'); - меняет режим предосмотра Урона / Лечения. * где 'MODE' - режим, варианты: * 'RANGE' - показывает мин. и макс. урон (зависит от Разброса скила); * 'VALUE' - показывает конкретное значение урона. * ---------------------------------------------------------------------------- * ----Версия 3.0.0 * --Исправлены баги: * 1. Баг с невозможностью использовать предметы из-за ошибки. * --Новый функционал: * 1. Добавлена совместимость с плагином WeaponSkill. * --Прочее: * 1. В настройках плагина добавлена возможность указать, отображать ли критический урон при предосмотре. * 2. В настройках плагина добавлена возможность указать, используется ли плагин WeaponSkill. * ---------------------------------------------------------------------------- * * @param skillDamagePreviewOn * @type boolean * @desc Включен ли предосмотр урона со старта игры. * @default true * * @param skillIsCritsAffectPreview * @type boolean * @desc Отображать ли критический урон при предосмотре. * @default false * * @param skillIsWeaponSkillUsed * @type boolean * @desc Используется ли плагин WeaponSkill * @default false * * @param previewMode * @type text * @desc Вариант предосмотра урона: или RANGE (мин. и макс. урон) или VALUE (фикс-е значение урона). * @default RANGE * * @param skillDamagePreviewPicNumber * @type number * @desc Номер картинки, что назначается предосмотру урона. * @default 81 * * @param skillDamagePreviewCoordX * @type number * @desc Координата X картинки предосмотра урона. * @default 600 * * @param skillDamagePreviewCoordY * @type number * @desc Координата Y картинки предосмотра урона. * @default 300 * * @param enemyDamageWord * @type text * @desc Текст при выборе скила на Врага. * @default Урон * * @param allyDamageWord * @type text * @desc Текст при выборе скила на Союзника. * @default Лечение * * @param preDamageWord * @type text * @desc Текст перед значениями урона. * @default , ~Σ: * * @param betweenMinMaxDamageWord * @type text * @desc Текст между мин. и макс. уроном. * @default ... * * @param normalColorTag * @type number * @desc Цветовой код (\C[?]) обычного текста . * @default 0 * * @param enemyDamageWordColorTag * @type number * @desc Цветовой код (\C[?]) обычного текста скила на Врага. * @default 10 * * @param allyDamageWordColorTag * @type number * @desc Цветовой код (\C[?]) обычного текста скила на Союзника. * @default 11 * * @param minDamageColorTag * @type number * @desc Цветовой код (\C[?]) минимального урона. * @default 14 * * @param betweenDamageColorTag * @type number * @desc Цветовой код (\C[?]) текста между мин. и макс. уроном. * @default 27 * * @param maxDamageColorTag * @type number * @desc Цветовой код (\C[?]) максимального урона. * @default 27 */ var Imported = Imported || {}; Imported.DKR_SkillDamagePreview = true; var DKR = DKR || {}; DKR.SkillDamagePreview = DKR.SkillDamagePreview || {}; DKR.SkillDamagePreview.version = 3.0; DKR.SkillDamagePreview.parameters = PluginManager.parameters('DKR_SkillDamagePreview_MZ_3.0'); ( () => { DKR.SkillDamagePreview.skillDamagePreviewOn = (DKR.SkillDamagePreview.parameters['skillDamagePreviewOn']=== 'true') ? true : false; DKR.SkillDamagePreview.previewMode = DKR.SkillDamagePreview.parameters['previewMode'] || 'RANGE'; DKR.SkillDamagePreview.skillIsCritsAffectPreview = (DKR.SkillDamagePreview.parameters['skillIsCritsAffectPreview']=== 'true') ? true : false; DKR.SkillDamagePreview.skillIsWeaponSkillUsed = (DKR.SkillDamagePreview.parameters['skillIsWeaponSkillUsed']=== 'true') ? true : false; DKR.SkillDamagePreview.selectedSkill = null; DKR.SkillDamagePreview.isTargetEnemy = true; let skillDamagePreviewPicNumber = Number(DKR.SkillDamagePreview.parameters['skillDamagePreviewPicNumber']) || 81; let skillDamagePreviewCoordX = Number(DKR.SkillDamagePreview.parameters['skillDamagePreviewCoordX']) || 600; let skillDamagePreviewCoordY = Number(DKR.SkillDamagePreview.parameters['skillDamagePreviewCoordY']) || 300; const skillDamagePreviewOrigin = 0; const skillDamagePreviewScaleX = 100; const skillDamagePreviewScaleY = 100; const skillDamagePreviewOpacity = 255; const skillDamagePreviewBlendMode = 0; const defaultAttackSkillId = 1; let textPictureText = ''; let normalColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['normalColorTag']) + ']' || '\\C[0]'; let enemyDamageWordColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['enemyDamageWordColorTag']) + ']' || '\\C[10]'; let allyDamageWordColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['allyDamageWordColorTag']) + ']' || '\\C[11]'; let minDamageColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['minDamageColorTag']) + ']' || '\\C[14]'; let betweenDamageColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['betweenDamageColorTag']) + ']' || '\\C[27]'; let maxDamageColorTag = '\\C[' + Number(DKR.SkillDamagePreview.parameters['maxDamageColorTag']) + ']' || '\\C[18]'; let enemyDamageWord = DKR.SkillDamagePreview.parameters['enemyDamageWord'] || 'Урон'; let allyDamageWord = DKR.SkillDamagePreview.parameters['allyDamageWord'] || 'Лечение'; let preDamageWord = DKR.SkillDamagePreview.parameters['preDamageWord'] || ', ~Σ:'; let betweenMinMaxDamageWord = DKR.SkillDamagePreview.parameters['betweenMinMaxDamageWord'] || '...'; let isSelectedObjectSkill = false; DKR.SkillDamagePreview.Window_SkillList__UpdateHelp = Window_SkillList.prototype.updateHelp; Window_SkillList.prototype.updateHelp = function(){ DKR.SkillDamagePreview.Window_SkillList__UpdateHelp.call(this); if(undefined === this.item()){ console.log('DKR.SkillDamagePreview: skill undefined...'); return false; } DKR.SkillDamagePreview.selectedSkill = this.item(); isSelectedObjectSkill = true; } DKR.SkillDamagePreview.setAttack = Game_Action.prototype.setAttack; Game_Action.prototype.setAttack = function() { DKR.SkillDamagePreview.setAttack.call(this); isSelectedObjectSkill = true; let weaponSkillId = defaultAttackSkillId; if(true === DKR.SkillDamagePreview.skillIsWeaponSkillUsed){ let actor = BattleManager._currentActor; if(false === actor.hasNoWeapons()){ let weapon = actor.weapons()[0]; try{ weaponSkillId = weapon.meta.skill_id; }catch(error){ weaponSkillId = defaultAttackSkillId; } if(undefined === weaponSkillId){ weaponSkillId = defaultAttackSkillId; } } } DKR.SkillDamagePreview.selectedSkill = $dataSkills[weaponSkillId]; }; DKR.SkillDamagePreview.Window_BattleEnemy__select = Window_BattleEnemy.prototype.select; Window_BattleEnemy.prototype.select = function(index){ DKR.SkillDamagePreview.Window_BattleEnemy__select.call(this, index); if(true === DKR.SkillDamagePreview.skillDamagePreviewOn && index > -1){ DKR.SkillDamagePreview.isTargetEnemy = true; DKR.SkillDamagePreview.showSkillDamagePreview(index); } } DKR.SkillDamagePreview.Window_BattleActor__select = Window_BattleActor.prototype.select; Window_BattleActor.prototype.select = function(index){ DKR.SkillDamagePreview.Window_BattleActor__select.call(this, index); if(true === DKR.SkillDamagePreview.skillDamagePreviewOn && index > -1){ DKR.SkillDamagePreview.isTargetEnemy = false; DKR.SkillDamagePreview.showSkillDamagePreview(index); } } DKR.SkillDamagePreview.Window_BattleEnemy__hide = Window_BattleEnemy.prototype.hide; Window_BattleEnemy.prototype.hide = function() { DKR.SkillDamagePreview.Window_BattleEnemy__hide.call(this); $gameScreen.erasePicture(skillDamagePreviewPicNumber); isSelectedObjectSkill = false; }; DKR.SkillDamagePreview.Window_BattleActor__hide = Window_BattleActor.prototype.hide; Window_BattleActor.prototype.hide = function() { DKR.SkillDamagePreview.Window_BattleActor__hide.call(this); $gameScreen.erasePicture(skillDamagePreviewPicNumber); isSelectedObjectSkill = false; }; DKR.SkillDamagePreview.Scene_Battle__onItemOk = Scene_Battle.prototype.onItemOk; Scene_Battle.prototype.onItemOk = function() { DKR.SkillDamagePreview.Scene_Battle__onItemOk.call(this); $gameScreen.erasePicture(skillDamagePreviewPicNumber); isSelectedObjectSkill = false; }; DKR.SkillDamagePreview.showSkillDamagePreview = function(enemyIndex){ if(false === isSelectedObjectSkill){ return false; } let enemy = null; let enemiesTroop = null; if(true === DKR.SkillDamagePreview.isTargetEnemy){ enemiesTroop = $gameTroop.aliveMembers(); enemy = enemiesTroop[enemyIndex]; }else{ enemy = $gameParty.members()[enemyIndex]; } let actor = BattleManager._currentActor; let skill = DKR.SkillDamagePreview.selectedSkill; if(null === actor){ return false; } let skillSkipOrSimpleFormula = parseSkillNoteForSOrSF(skill); if('SKIP' === skillSkipOrSimpleFormula){ return false; }else if('NONE' === skillSkipOrSimpleFormula){ skillSkipOrSimpleFormula = null; } let isSkillCritical = Math.random() < calcIsSkillCritical(enemy, actor, skill); if(false === DKR.SkillDamagePreview.skillIsCritsAffectPreview){ isSkillCritical = false; } let totalDamageValue = 0; let currentDamageValue = 0; for(let n = 0; n < skill.repeats; n++){ currentDamageValue = makeDamageValue(enemy, actor, skill, isSkillCritical, skillSkipOrSimpleFormula); totalDamageValue += currentDamageValue; } let [minDamage, maxDamage] = getMinMaxDamage(totalDamageValue, skill.damage.variance); drawSkillDamagePreviewOnEnemy(minDamage, maxDamage); } let parseSkillNoteForSOrSF = function(skill){ const tag = 'SkillDamagePreviewSimpleFormula'; const skipWord = 'SkillDamagePreviewSKIP'; let notedata = skill.note.split(/[\r\n]+/); let formulaText = 'NONE'; if(true === skill.note.includes(skipWord)){ formulaText = 'SKIP'; return formulaText; } let matchCount = 0; for (let i = 0; i < notedata.length; i++) { let line = notedata[i]; if (notedata[i].match(tag)) { matchCount++; if(2 === matchCount){ break; }else{ formulaText = '\r\n'; continue; } } if(1 === matchCount){ formulaText += notedata[i].trim() + '\r\n' } } return formulaText; } let getMinMaxDamage = function(damage, variance){ let minDamage = 0; let maxDamage = 0; let minMaxDamage = []; let diffByVariance = 0; if('RANGE' === DKR.SkillDamagePreview.previewMode){ let diffByVariance = Math.round( damage * (variance / 100) ); minDamage = Math.round( damage - (diffByVariance + (diffByVariance / 4) ) ); maxDamage = Math.round( damage + diffByVariance ); }else if('VALUE' === DKR.SkillDamagePreview.previewMode){ minDamage = damage; maxDamage = damage; } minMaxDamage = [minDamage, maxDamage]; return minMaxDamage; } let drawSkillDamagePreviewOnEnemy = function(minDamage, maxDamage){ let damageTypeWord = ''; let damageTypeColorTag = ''; if(true === DKR.SkillDamagePreview.isTargetEnemy){ damageTypeWord = enemyDamageWord; damageTypeColorTag = enemyDamageWordColorTag; }else{ minDamage = Math.abs(minDamage); maxDamage = Math.abs(maxDamage); damageTypeWord = allyDamageWord; damageTypeColorTag = allyDamageWordColorTag; } textPictureText = ` ${damageTypeColorTag}${damageTypeWord}${betweenDamageColorTag}${preDamageWord} ${minDamageColorTag}${minDamage}${betweenDamageColorTag}${betweenMinMaxDamageWord}${maxDamageColorTag}${maxDamage}${normalColorTag}`; $gameScreen.showPicture(skillDamagePreviewPicNumber, '', skillDamagePreviewOrigin, skillDamagePreviewCoordX, skillDamagePreviewCoordY, skillDamagePreviewScaleX, skillDamagePreviewScaleY, skillDamagePreviewOpacity, skillDamagePreviewBlendMode); } DKR.SkillDamagePreview.enableSkillDamagePreview = function(){ DKR.SkillDamagePreview.skillDamagePreviewOn = true; } DKR.SkillDamagePreview.dissableSkillDamagePreview = function(){ DKR.SkillDamagePreview.skillDamagePreviewOn = false; } DKR.SkillDamagePreview.changePreviewMode = function(pMode){ DKR.SkillDamagePreview.previewMode = pMode; } //---COPY PAST CORELIB: BEGIN let makeDamageValue = function(target, actor, skill, isCritical, skillDamageSimpleFormula) { const item = skill; const baseValue = evalDamageFormula(target, actor, skill, skillDamageSimpleFormula); let value = baseValue * calcElementRate(target, actor, skill); if (isPhysical(skill)) { value *= target.pdr; } if (isMagical(skill)) { value *= target.mdr; } if (baseValue < 0) { value *= target.rec; } if (isCritical) { value = applyCritical(value); } value = applyVariance(value, item.damage.variance); value = applyGuard(value, target); value = Math.round(value); return value; }; let calcIsSkillCritical = function(target, actor, skill) { return skill.damage.critical ? actor.cri * (1 - target.cev) : 0; }; let evalDamageFormula = function(target, actor, skill, skillDamageSimpleFormula) { try { let skillDamageFormula = null; if(null === skillDamageSimpleFormula){ skillDamageFormula = skill.damage.formula; }else{ skillDamageFormula = skillDamageSimpleFormula; } const a = actor; const b = target; const v = $gameVariables._data; const sign = [3, 4].includes(skill.damage.type) ? -1 : 1; const value = Math.max(eval(skillDamageFormula), 0) * sign; return isNaN(value) ? 0 : value; } catch (e) { return 0; } }; let calcElementRate = function(target, actor, skill) { if (skill.damage.elementId < 0) { return elementsMaxRate(target, actor.attackElements()); } else { return target.elementRate(skill.damage.elementId); } }; let elementsMaxRate = function(target, elements) { if (elements.length > 0) { const rates = elements.map(elementId => target.elementRate(elementId)); return Math.max(...rates); } else { return 1; } }; let isPhysical = function(skill) { return skill.hitType === Game_Action.HITTYPE_PHYSICAL; }; let isMagical = function(skill) { return skill.hitType === Game_Action.HITTYPE_MAGICAL; }; let applyCritical = function(damage) { return damage * 3; }; let applyVariance = function(damage, variance) { const amp = Math.floor(Math.max((Math.abs(damage) * variance) / 100, 0)); const v = Math.randomInt(amp + 1) + Math.randomInt(amp + 1) - amp; return damage >= 0 ? damage + v : damage - v; }; let applyGuard = function(damage, target) { return damage / (damage > 0 && target.isGuard() ? 2 * target.grd : 1); }; //---COPY PAST CORELIB: END //---Thanks to Yoji Ojima: BEGIN const _Game_Picture_show = Game_Picture.prototype.show; Game_Picture.prototype.show = function() { _Game_Picture_show.apply(this, arguments); if (this._name === "" && textPictureText) { this.mzkp_text = textPictureText; this.mzkp_textChanged = true; textPictureText = ''; } }; const _Sprite_Picture_destroy = Sprite_Picture.prototype.destroy; Sprite_Picture.prototype.destroy = function() { destroyTextPictureBitmap(this.bitmap); _Sprite_Picture_destroy.apply(this, arguments); }; const _Sprite_Picture_updateBitmap = Sprite_Picture.prototype.updateBitmap; Sprite_Picture.prototype.updateBitmap = function() { _Sprite_Picture_updateBitmap.apply(this, arguments); if (this.visible && this._pictureName === "") { const picture = this.picture(); const text = picture ? picture.mzkp_text || "" : ""; const textChanged = picture && picture.mzkp_textChanged; if (this.mzkp_text !== text || textChanged) { this.mzkp_text = text; destroyTextPictureBitmap(this.bitmap); this.bitmap = createTextPictureBitmap(text); picture.mzkp_textChanged = false; } } else { this.mzkp_text = ""; } }; function createTextPictureBitmap(text) { const tempWindow = new Window_Base(new Rectangle()); const size = tempWindow.textSizeEx(text); tempWindow.padding = 0; tempWindow.move(0, 0, size.width, size.height); tempWindow.createContents(); tempWindow.drawTextEx(text, 0, 0, 0); const bitmap = tempWindow.contents; tempWindow.contents = null; tempWindow.destroy(); bitmap.mzkp_isTextPicture = true; return bitmap; } function destroyTextPictureBitmap(bitmap) { if (bitmap && bitmap.mzkp_isTextPicture) { bitmap.destroy(); } } //---Thanks to Yoji Ojima: END })();
Скриншоты:
Спойлер Как это выглядит в игре:
Изменения
Спойлер Версия 5.0:Изменения в Версии 5.0
Добавлена доп. совместимость с боевыми плагинами Yanfly, улучшена совместимость с плагином WeaponSkill, добавлена возможность в скилле указывать принудительный цвет текста. Введены новые параметры плагина.
Спойлер Версия 3.0:Изменения в Версии 3.0
Исправлены баги:
1. Баг с невозможностью использовать предметы из-за ошибки.
Новый функционал:
1. Добавлена совместимость с плагином WeaponSkill.
Прочее:
1. В настройках плагина добавлена возможность указать, отображать ли критический урон при предосмотре (по-умолчанию: отключено).
2. В настройках плагина добавлена возможность указать, используется ли плагин WeaponSkill (по-умолчанию: отключено).
Спойлер Версия 2.0:Изменения в Версии 2.0
Исправлены баги:
1. Баг с автоматическим выбором мертвого Врага как цели для случаев, если противников несколько.
2. Баг с не удалением текста лечения Союзника в случае отмены скила.
Новый функционал:
1. Возможность в Примечании скила прописать в теге SkillDamagePreviewSimpleFormula формулу урона - в этом случае
для предосмотра урона для данного скила будет использована именно эта формула вместо формулы самого скила.
2. Возможность в Примечании скила прописать SkillDamagePreviewSKIP для отмены предосмотра урона для данного скила.
Прочее:
1. Добавлена возможность настройки плагина при помощи параметров (цвета, текста, координаты).
Загрузка:
Спойлер Ссылки на загрузку, версия 5.0(только MV) и (3.0 (Старые версии удалены!):
Условия поставки плагина:
Поставляется AS-IS.
Вся ответственность при использовании - на Пользователе!
!
Совместимость с другими плагинами Авторы не гарантируют (однако, с плагинами DKR_PictureOnSkillObserve и WeaponSkill данный плагин совместим...с версии плагина 3.0). С версии 5.0 повышена совместимость с боевыми плагинами Yanfly, но полная совместимость все еще не гарантируется !
Спойлер Лирическое отступление:Странно, что такой плагин никто не сделал...ну или я плохо гуглил.
Всего-то перетащить из кор-либы самого мейкера функцию подсчета урона (и все зависимые функции).
Создание окон я все еще не освоил и текст, опять, отображается картинкой.
...И оказалось, что у GALVа есть похожий плагин, вот это прикол. =)
Благодарности:
Alx_Yago - за помощь в создании версии 5.0, идею плагина и помощь в поиске багов.
Dmy - за помощь в создании версии 5.0.
Yoji Ojima - за технику отображения текста картинкой.
Социальные закладки